#include "socket.h"
#include <arpa/inet.h>
#include <cassert>
#include <cstring>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>

#include <cstring>

const char *Socket::getLocalIP(const char *interface) {
    static char ipstr[INET_ADDRSTRLEN];
    struct ifaddrs *ifap, *ifa;
    getifaddrs(&ifap);
    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr && ifa->ifa_name && !strcmp(ifa->ifa_name, interface)) {
            if (ifa->ifa_addr->sa_family == AF_INET) {
                struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
                inet_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN);
                freeifaddrs(ifap);
                return ipstr;
            }
        }
    }
    freeifaddrs(ifap);
    return 0;
}

// 获取本机IP地址的最后一个数值
uint8_t Socket::getLocalIPLastOctet(const char *interface) {
    const char *ipStr = getLocalIP(interface);
    std::string ip(ipStr);
    size_t pos = ip.rfind('.');
    if (pos != std::string::npos) {
        std::string lastOctetStr = ip.substr(pos + 1);
        uint8_t lastOctet = static_cast<uint8_t>(std::stoi(lastOctetStr));
        return lastOctet;
    }
    return 0;
}

Socket::Socket() : fd_(-1) {}

Socket::~Socket() {
    if (fd_ != -1) {
        close(fd_);
        fd_ = -1;
    }
}

void Socket::set_fd(int fd) { fd_ = fd; }

int Socket::fd() const { return fd_; }

std::string Socket::get_addr() const {
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    socklen_t len = sizeof(addr);
    if (getpeername(fd_, (struct sockaddr *)&addr, &len) == -1) {
        return "";
    }
    std::string ret(inet_ntoa(addr.sin_addr));
    ret += ":";
    ret += std::to_string(htons(addr.sin_port));
    return ret;
}

size_t Socket::RecvBufSize() const {
    size_t size = -1;
    if (ioctl(fd_, FIONREAD, &size) == -1) {
        perror("Socket get recv buf size failed");
    }
    return size;
}

RC Socket::create() {
    assert(fd_ == -1);
    fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (fd_ == -1) {
        perror("Failed to create socket");
        return RC_SOCKET_ERROR;
    }
    return RC_SUCCESS;
}

RC Socket::bind(const char *ip, uint16_t port) const {
    assert(fd_ != -1);
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);
    if (::bind(fd_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("Failed to bind socket");
        return RC_SOCKET_ERROR;
    }
    return RC_SUCCESS;
}

RC Socket::listen() const {
    assert(fd_ != -1);
    if (::listen(fd_, SOMAXCONN) == -1) {
        perror("Failed to listen socket");
        return RC_SOCKET_ERROR;
    }
    return RC_SUCCESS;
}

RC Socket::accept(int &clnt_fd) const {
    // TODO: non-blocking
    assert(fd_ != -1);
    clnt_fd = ::accept(fd_, NULL, NULL);
    if (clnt_fd == -1) {
        perror("Failed to accept socket");
        return RC_SOCKET_ERROR;
    }
    return RC_SUCCESS;
}

RC Socket::connect(const char *ip, uint16_t port) const {
    // TODO: non-blocking
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);
    if (::connect(fd_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("Failed to connect socket");
        return RC_SOCKET_ERROR;
    }
    return RC_SUCCESS;
}
